#include "gdt.h"

extern void load_gdt(void);

gdt_entry_t gdt_table[GDT_TABLE_SIZE];

void init_GDT(){
	
	/*Null segment.*/
	gdt_table[0].base_l = (0 & 0xFFFF);
	gdt_table[0].base_m = (0 >> 16) & 0xFF;
	gdt_table[0].base_h = (0 >> 24) & 0xFF;

	gdt_table[0].limit_l = (0 & 0xFFFF);
	gdt_table[0].granularity = (0 >> 16) & 0x0F;

	gdt_table[0].granularity |= 0 & 0xF0;
	gdt_table[0].access_mode = 0;
	
	/*Kernel Code segment.*/
	gdt_table[1].base_l = (GDT_BASE & 0xFFFF);
	gdt_table[1].base_m = (GDT_BASE >> 16) & 0xFF;
	gdt_table[1].base_h = (GDT_BASE >> 24) & 0xFF;

	gdt_table[1].limit_l = (GDT_LIMIT & 0xFFFF);
	gdt_table[1].granularity = (GDT_LIMIT >> 16) & 0x0F;

	gdt_table[1].granularity |= GDT_GRAN & 0xF0;
	gdt_table[1].access_mode = GDT_KERNEL_CS_ACCESS;

	/*Kernel Data segment.*/
	gdt_table[2].base_l = (GDT_BASE & 0xFFFF);
	gdt_table[2].base_m = (GDT_BASE >> 16) & 0xFF;
	gdt_table[2].base_h = (GDT_BASE >> 24) & 0xFF;

	gdt_table[2].limit_l = (GDT_LIMIT & 0xFFFF);
	gdt_table[2].granularity = (GDT_LIMIT >> 16) & 0x0F;

	gdt_table[2].granularity |= GDT_GRAN & 0xF0;
	gdt_table[2].access_mode = GDT_KERNEL_DS_ACCESS;

	/*User Code segment.*/
	gdt_table[3].base_l = (GDT_BASE & 0xFFFF);
	gdt_table[3].base_m = (GDT_BASE >> 16) & 0xFF;
	gdt_table[3].base_h = (GDT_BASE >> 24) & 0xFF;

	gdt_table[3].limit_l = (GDT_LIMIT & 0xFFFF);
	gdt_table[3].granularity = (GDT_LIMIT >> 16) & 0x0F;

	gdt_table[3].granularity |= GDT_GRAN & 0xF0;
	gdt_table[3].access_mode = GDT_USER_CS_ACCESS;

	/*User data segment.*/
	gdt_table[4].base_l = (GDT_BASE & 0xFFFF);
	gdt_table[4].base_m = (GDT_BASE >> 16) & 0xFF;
	gdt_table[4].base_h = (GDT_BASE >> 24) & 0xFF;

	gdt_table[4].limit_l = (GDT_LIMIT & 0xFFFF);
	gdt_table[4].granularity = (GDT_LIMIT >> 16) & 0x0F;

	gdt_table[4].granularity |= GDT_GRAN & 0xF0;
	gdt_table[4].access_mode = GDT_USER_DS_ACCESS;
	
	GDTR.table_limit = (GDT_TABLE_SIZE * sizeof(struct _gdt_gdtr)) - 1;
	GDTR.gdt_ptr     = (unsigned int)gdt_table;
	
	load_gdt();
}

inline void load_gdt(void)
{
	asm("lgdtl %0           \n"
		/* Reload DATA segment */
		"movw %1,   %%ax    \n"
		"movw %%ax, %%ds    \n"
		"movw %%ax, %%fs    \n"
		"movw %%ax, %%gs    \n"
		"movw %%ax, %%ss    \n"
		"movw %%ax, %%es    \n"
		/* Reload CODE segment */
		"ljmp %2, $reloadCS \n"
		"reloadCS:            "
			: : "m" (GDTR), "I" (KERNEL_DS), "I" (KERNEL_CS) : "eax");
}
